package tech.horgee.log.aop;


import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.spring.SpringUtil;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import tech.horgee.json.utils.JsonUtils;
import tech.horgee.log.events.OperLogEvent;

import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;

/**
 * 日志记录
 */
@Slf4j
@Aspect
@Configuration
public class LogAspect {

    // 不入操作日志表的url关键字
    public static final String[] EXCLUDE_KEYWORDS = {"page", "list", "current"};

    @Pointcut("execution(* tech..*.controller..*.*(..))")
    public void print() {

    }

    @Before("print()")
    public void before(JoinPoint joinPoint) {
        String method = joinPoint.getSignature().getName();
        String className = joinPoint.getSignature().getDeclaringTypeName();
        log.info("[LOG]请求方法：{}.{}() => \n{}", className, method, getRequestParam(joinPoint));
    }

    @AfterReturning(value = "print()", returning = "res")
    public void afterReturning(JoinPoint joinPoint, Object res) {
        handleOperateLog(joinPoint, res, null);
    }

    @AfterThrowing(value = "print()", throwing = "e")
    public void afterThrowing(JoinPoint joinPoint, Exception e) {
        handleOperateLog(joinPoint, null, e);
    }

    private void handleOperateLog(JoinPoint joinPoint, Object res, Exception e) {
        ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = requestAttributes.getRequest();
        String url = request.getRequestURI();
        for (String key : EXCLUDE_KEYWORDS) {
            if (url.contains(key)) return;
        }
        String requestMethod = request.getMethod();
        OperLogEvent logEvent = new OperLogEvent();
        logEvent.setRequestMethod(requestMethod);
        logEvent.setOperUrl(url);
        logEvent.setClassName(joinPoint.getSignature().getDeclaringTypeName());
        logEvent.setMethod(joinPoint.getSignature().getName());
        logEvent.setOperTime(LocalDateTime.now());
        logEvent.setStatus(Boolean.TRUE);
        logEvent.setOperParam(StrUtil.sub(getRequestParam(joinPoint), 0, 2000));
        logEvent.setJsonResult(StrUtil.sub(JsonUtils.toJsonPrettyStr(res), 0, 2000));
        if (e != null) {
            logEvent.setStatus(Boolean.FALSE);
            logEvent.setErrorMsg(e.getMessage());
        }
        SpringUtil.getApplicationContext().publishEvent(logEvent);
    }

    private String getRequestParam(JoinPoint joinPoint) {
        Object[] args = joinPoint.getArgs();
        if (args.length == 0) return "";
        List<Object> params = Arrays.stream(args).filter(i ->
                {
                    if (Objects.isNull(i)) return true;
                    String className = i.getClass().getName();
                    return className.contains("horgee")
                            || className.contains("java.lang");
                }
        ).toList();
        return JsonUtils.toJsonPrettyStr(params);
    }
}
